/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2023-06-21     cheng       the first version
 */
#include "board.h"
#include "drv_pwm_inputcapture.h"
#ifdef RT_USING_PWM_INPUT_CAPTURE

#define DRV_DEBUG
#define LOG_TAG             "drv.pwm_inputcap"
#include <drv_log.h>

#if !defined(BSP_USING_PWM_INPUTCAPTURE1) && !defined(BSP_USING_PWM_INPUTCAPTURE2) \
    && !defined(BSP_USING_PWM_INPUTCAPTURE3) && !defined(BSP_USING_PWM_INPUTCAPTURE4) && !defined(BSP_USING_PWM_INPUTCAPTURE5)
    #error "Please define at least one BSP_USING_PULSE_ENCODERx"
    /* this driver can be disabled at menuconfig -> RT-Thread Components -> Device Drivers */
#endif

enum
{
#ifdef BSP_USING_PWM_INPUTCAPTURE1
    PWM_INPUTCAPTURE1_INDEX,
#endif
#ifdef BSP_USING_PWM_INPUTCAPTURE2
    PWM_INPUTCAPTURE2_INDEX,
#endif
#ifdef BSP_USING_PWM_INPUTCAPTURE3
    PWM_INPUTCAPTURE3_INDEX,
#endif
#ifdef BSP_USING_PWM_INPUTCAPTURE4
    PWM_INPUTCAPTURE4_INDEX,
#endif
#ifdef BSP_USING_PWM_INPUTCAPTURE5
    PWM_INPUTCAPTURE5_INDEX,
#endif
};


static struct gd32_pwm_inputcapture_device gd32_pwm_inputcapture_obj[] =
{
#ifdef BSP_USING_PWM_INPUTCAPTURE1
        PWM_INPUTCAPTURE1_CONFIG,
#endif
#ifdef BSP_USING_PWM_INPUTCAPTURE2
        PWM_INPUTCAPTURE2_CONFIG,
#endif
#ifdef BSP_USING_PWM_INPUTCAPTURE3
        PWM_INPUTCAPTURE3_CONFIG,
#endif
#ifdef BSP_USING_PWM_INPUTCAPTURE4
        PWM_INPUTCAPTURE4_CONFIG,
#endif
#ifdef BSP_USING_PWM_INPUTCAPTURE5
        PWM_INPUTCAPTURE5_CONFIG,
#endif
};

rt_err_t pwm_inputcap_init(struct pwm_inputcapture_device *pwm_incap)
{
    uint32_t sys_clk_freq;
    uint32_t timer_prescaler = 1;
    uint32_t trigger_ch;
    timer_parameter_struct TimerConfig;
    timer_ic_parameter_struct TimerICConfig;
    struct gd32_pwm_inputcapture_device *pwm_incap_device;
    pwm_incap_device = (struct gd32_pwm_inputcapture_device*)pwm_incap;

    rcu_periph_clock_enable(pwm_incap_device->timer_rcu);
    rcu_periph_clock_enable(pwm_incap_device->GPIO_rcu);

    gpio_init(pwm_incap_device->GPIOx, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, pwm_incap_device->PINx);

    sys_clk_freq = rcu_clock_freq_get(CK_SYS);
    LOG_I("system clock frequency:%d", sys_clk_freq);

    TimerConfig.alignedmode = TIMER_COUNTER_EDGE;
    TimerConfig.clockdivision = TIMER_CKDIV_DIV1;
    TimerConfig.counterdirection = TIMER_COUNTER_UP;
    TimerConfig.period = 65535U;
    do{
        if(sys_clk_freq / timer_prescaler / TimerConfig.period < pwm_incap_device->input_freq_min)
            break;
        if(timer_prescaler == 65536)
        {
            rt_kprintf("can not configure the prescaler for input signal frequency:%dhz\n", pwm_incap_device->input_freq_min);
            return RT_ERROR;
        }
        timer_prescaler++;
    }while(1);
    TimerConfig.prescaler = timer_prescaler-1;
    TimerConfig.repetitioncounter = 0;
    timer_init(pwm_incap_device->timerx, &TimerConfig);
    LOG_I("%s timer prescaler:%d", pwm_incap_device->name, timer_prescaler);

    TimerICConfig.icfilter = 10;
    TimerICConfig.icpolarity = TIMER_IC_POLARITY_RISING;
    TimerICConfig.icprescaler = TIMER_IC_PSC_DIV1;
    TimerICConfig.icselection = TIMER_IC_SELECTION_DIRECTTI;
    timer_input_pwm_capture_config(pwm_incap_device->timerx, pwm_incap_device->input_ch, &TimerICConfig);
    timer_interrupt_flag_clear(pwm_incap_device->timerx, TIMER_INT_FLAG_UP);
    timer_interrupt_enable(pwm_incap_device->timerx,TIMER_INT_UP);

    trigger_ch = ((pwm_incap_device->input_ch == TIMER_CH_0) ? TIMER_SMCFG_TRGSEL_CI0FE0 : TIMER_SMCFG_TRGSEL_CI1FE1);
    timer_input_trigger_source_select(pwm_incap_device->timerx, trigger_ch);
    timer_slave_mode_select(pwm_incap_device->timerx, TIMER_SLAVE_MODE_RESTART);
    timer_external_trigger_config(pwm_incap_device->timerx,TIMER_EXT_TRI_PSC_OFF,TIMER_ETP_RISING,10);

    NVIC_SetPriority(pwm_incap_device->timerx_irqn, 3);
    NVIC_EnableIRQ(pwm_incap_device->timerx_irqn);

    timer_enable(pwm_incap_device->timerx);

    return RT_EOK;
}

rt_err_t pwm_inputcap_open(struct pwm_inputcapture_device *pwm_incap)
{

}

rt_err_t pwm_inputcap_close(struct pwm_inputcapture_device *pwm_incap)
{

}

void pwm_inputcapture_update_isr(struct gd32_pwm_inputcapture_device *device)
{
//    static uint16_t wait1_i = 0, wait2_i = 0;
    uint32_t width_ch;
    /* TIM Update event */
    if (timer_interrupt_flag_get(device->timerx, TIMER_INT_FLAG_UP) != RESET)
    {
        timer_interrupt_flag_clear(device->timerx, TIMER_INT_FLAG_UP);
        device->pwm_inputcap.pulse_param.pulsecycle_us = timer_channel_capture_value_register_read(device->timerx, device->input_ch);
        width_ch = ((device->input_ch == TIMER_CH_0) ? (TIMER_CH_1) : (TIMER_CH_0));
        device->pwm_inputcap.pulse_param.pulsewidth_us = timer_channel_capture_value_register_read(device->timerx, width_ch);
        rt_hw_pwm_inputcapture_isr(device);
//        if(device->timerx == TIMER1)
//        {
//            if(wait1_i++ == 1000)
//            {
//                wait1_i = 0;
//                rt_kprintf("[%s] cycle:%d, width:%d\n",device->name, device->pwm_inputcap.pulse_param.pulsecycle_us, device->pwm_inputcap.pulse_param.pulsewidth_us);
//            }
//        }
//        else {
//            if(wait2_i++ == 1000)
//            {
//                wait2_i = 0;
//                rt_kprintf("[%s] cycle:%d, width:%d\n",device->name, device->pwm_inputcap.pulse_param.pulsecycle_us, device->pwm_inputcap.pulse_param.pulsewidth_us);
//            }
//        }
    }
}

#ifdef BSP_USING_PWM_INPUTCAPTURE1
void TIMER1_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();
    pwm_inputcapture_update_isr(&gd32_pwm_inputcapture_obj[PWM_INPUTCAPTURE1_INDEX]);
    /* leave interrupt */
    rt_interrupt_leave();
}
#endif
#ifdef BSP_USING_PWM_INPUTCAPTURE2
void TIMER2_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();
    pwm_inputcapture_update_isr(&gd32_pwm_inputcapture_obj[PWM_INPUTCAPTURE2_INDEX]);
    /* leave interrupt */
    rt_interrupt_leave();
}
#endif
#ifdef BSP_USING_PWM_INPUTCAPTURE3
void TIMER3_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();
    pwm_inputcapture_update_isr(&gd32_pwm_inputcapture_obj[PWM_INPUTCAPTURE3_INDEX]);
    /* leave interrupt */
    rt_interrupt_leave();
}
#endif
#ifdef BSP_USING_PWM_INPUTCAPTURE4
void TIMER4_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();
    pwm_inputcapture_update_isr(&gd32_pwm_inputcapture_obj[PWM_INPUTCAPTURE4_INDEX]);
    /* leave interrupt */
    rt_interrupt_leave();
}
#endif
#ifdef BSP_USING_PWM_INPUTCAPTURE5
void TIMER5_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();
    pwm_inputcapture_update_isr(&gd32_pwm_inputcapture_obj[PWM_INPUTCAPTURE5_INDEX]);
    /* leave interrupt */
    rt_interrupt_leave();
}
#endif
#ifdef BSP_USING_PWM_INPUTCAPTURE6
void TIMER6_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();
    pwm_inputcapture_update_isr(&gd32_pwm_inputcapture_obj[PWM_INPUTCAPTURE6_INDEX]);
    /* leave interrupt */
    rt_interrupt_leave();
}
#endif

static const struct pwm_inputcapture_ops _ops =
{
    .init = pwm_inputcap_init,
    .open = pwm_inputcap_open,
    .close = pwm_inputcap_close
};

int hw_pwm_inputcapture_init(void)
{
    int i;
    int result;
    result = RT_EOK;
    for (i = 0; i < sizeof(gd32_pwm_inputcapture_obj) / sizeof(gd32_pwm_inputcapture_obj[0]); i++)
    {
        gd32_pwm_inputcapture_obj[i].pwm_inputcap.ops = &_ops;

        if (rt_device_pwm_inputcapture_register(&gd32_pwm_inputcapture_obj[i].pwm_inputcap, gd32_pwm_inputcapture_obj[i].name, RT_NULL) != RT_EOK)
        {
            LOG_E("%s register failed", gd32_pwm_inputcapture_obj[i].name);
            result = -RT_ERROR;
        }
        else {
            LOG_I("%s register OK!", gd32_pwm_inputcapture_obj[i].name);
        }
    }

    return result;
}
INIT_DEVICE_EXPORT(hw_pwm_inputcapture_init);

#endif

